﻿/*
 * @Autor: PK
 * @Date: 2022/01/01 22:12:SS
 */

using System;
using Itinero;
using Itinero.LocalGeo;
using Itinero.Profiles;
using ShkSimulation.core.exceptions;
using ShkSimulation.core.template.model;
using ShkSimulation.carsharing.impl.elements;
using Vehicle = Itinero.Osm.Vehicles.Vehicle;

namespace ShkSimulation.carsharing.impl.model {

	public class RoadServiceRateHelper : ServiceRateHelper{
		
		public event Action<Route, Road> OnRouteSuccess;
		
		private Road CurrentRoad { get; init; }
		public RoadServiceRateModeEnum ServiceRateMode { get; set; }
		private Router osmRouter;
		private IProfileInstance ProfileInstance;
		
		public bool NavigateMode => UseNavigateMode();

		public static readonly int SERVICE_RATE_UPPER = 50;
		
		public static readonly int SERVICE_RATE_LOWER = 1;

		public RoadServiceRateHelper(Road road, Router router = null, IProfileInstance profileInstance = null) {
			if (profileInstance == null) {
				profileInstance = Vehicle.Car.Fastest();
			}
			if (router != null) {
				if (profileInstance == null) {
					string message = $"ProfileInstance是空，请传入RoadServiceRateHelper";
					Console.WriteLine(message);
					throw new ErrorParamException(message);
				}
				if (!router.SupportsAll(profileInstance)) {
					string message = $"导航文件{router.Db}不支持：{profileInstance.Profile.Name}";
					Console.WriteLine(message);
					throw new ErrorParamException(message);
				}
			}
			this.ProfileInstance = profileInstance;
			this.CurrentRoad = road;
			this.osmRouter = router;
			ServiceRateMode = router == null ? RoadServiceRateModeEnum.Stable : RoadServiceRateModeEnum.Navigate;
		}
		
		public TimeSpan GetAverageServiceTime() {
			if (NavigateMode) {
				return GetNavigateServiceRate();
			}
			return TimeSpan.FromHours(CurrentRoad.RoadLength / CurrentRoad.FreeSpeed);
		}

		private TimeSpan GetNavigateServiceRate() {
			Coordinate start = new Coordinate((float)CurrentRoad.LastStation.Latitude, (float)CurrentRoad.LastStation.Longitude);
			Coordinate end = new Coordinate((float)CurrentRoad.NextStation.Latitude, (float)CurrentRoad.NextStation.Longitude);
			Result<Route> calculate = osmRouter.TryCalculate(ProfileInstance, start, end);
			if (calculate.IsError) {
				Console.WriteLine("导航失败");
				throw new ErrorParamException("导航失败");
			}
			OnRouteSuccess?.Invoke(calculate.Value, CurrentRoad);
			return TimeSpan.FromSeconds(calculate.Value.TotalTime);
		}

		private bool UseNavigateMode() {
			return ServiceRateMode == RoadServiceRateModeEnum.Navigate &&
			       osmRouter != null && 
			       CurrentRoad.LastStation != null && 
			       CurrentRoad.NextStation != null;
		}

		public double GetStableServiceRate() {
			//获取新的Utilization
			double utilization = GetNewUtilization();
			double tempGama = 0.9330652505855433;
			double tempBeta = 0.3153075521948271;
			double speed;
			if (CurrentRoad.VehicleCount <= CurrentRoad.Capacity) {
				speed = CurrentRoad.FreeSpeed * 
				        Math.Exp(
					        (-1) * 
					        Math.Pow((CurrentRoad.VehicleCount + CurrentRoad.Capacity * utilization) / (CurrentRoad.Capacity * tempBeta), tempGama)
				        );
			} else {
				speed = CurrentRoad.FreeSpeed *
				        Math.Exp(
					        (-1) *
					        Math.Pow(1 / tempBeta, tempGama)
				        );
			}
			double ServiceRate = CurrentRoad.VehicleCount * speed / CurrentRoad.RoadLength;

			if (ServiceRate.Equals(double.NaN) || ServiceRate <= SERVICE_RATE_LOWER || ServiceRate >= SERVICE_RATE_UPPER) {
				ServiceRate = 25;
			}
			return ServiceRate;
		}

		private double GetNewUtilization() {
			if (CurrentRoad.ClockTime.Hour <= 6) {
				return 20;
			} else if (CurrentRoad.ClockTime.Hour <= 12) {
				return 60;
			} else if (CurrentRoad.ClockTime.Hour <= 18) {
				return 50;
			} else {
				return 80;
			}
		}
		
	}

}